06. ROS Services

ROS Services

Now that you've written your first ROS node, you've seen how publishing to a topic works, and you were able control the robotic arm by publishing to the /simple_arm/joint_2_position_controller/command topic. Next up, we'll see another node called arm_mover which implements the safe_move service to allow the arm to be controlled with service calls.

Defining services

A ROS service allows request/response communication to exist between nodes. Within the node providing the service, request messages are handled by functions or methods. Once the requests have been handled successfully, the node providing the service sends a message back to the requester node. In Python, a ROS service can be created using the following definition format:

service = rospy.Service('service_name', serviceClassName, handler)

Here, the service_name is the name given to the service. Other nodes will use this name to specify which service they are sending requests to.

The serviceClassName comes from the file name where the service definition exists. You will see more about this in the next classroom concept, but each service has a definition provided in an .srv file; this is a text file that provides the proper message type for both requests and responses.

The handler is the name of the function or method that handles the incoming service message. This function is called each time the service is called, and the message from the service call is passed to the handler as an argument. The handler should return an appropriate service response message.

Using Services

Services can be called directly from the command line, and you will see an example of this in the upcoming arm_mover classroom concepts.

On the other hand, to use a ROS service from within another node, you will define a ServiceProxy , which provides the interface for sending messages to the service:

service_proxy = rospy.ServiceProxy('service_name', serviceClassName)

One way the ServiceProxy can then be used to send requests is as follows:

msg = serviceClassNameRequest()
#update msg attributes here to have correct data
response = service_proxy(msg)

In the code above, a new service message is created by calling the serviceClassNameRequest() method. This method is provided by rospy, and its name is given by appending Request() to the name used for serviceClassName . Since the message is new, the message attributes should be updated to have the appropriate data. Next, the service_proxy can be called with the message, and the response stored.

For other ways to pass data to service_proxy , see the ROS documentation here .

Services quiz

Which of the following ROS nodes might best be implemented using a service?

SOLUTION:
  • A node for a lunar rover that shuts down a robotic arm by folding the arm and killing all related processes.
  • A node that sets a given parameter on request. For example, a node in turtlesim that sets the pen color in the turtlesim window.
  • A node which executes movement for a robotic arm, checking that the arm joints are within specified bounds.

Let's get started with the arm_mover code, so you can see how to combine the safe_move service along with publishers in a node!